#include "tft_hx8347.h"

#define CHRDEV_MINOR 0    // 次设备号
#define CHRDEV_COUNT 1    // 次设备号个数
#define CHRDEV_NAME  "TFT_HX8347G_Driver"  // 主设备名
#define SUB_DEV_NAME_1  "tft_hx8347g"        // 次设备名1
#define CHRDEV_CLASS_NAME "TFT_HX8347G_Class"

#define PIN_PROCESS  10
#define WRITE_BYTES  11
#define FILL_SCREEN  12
#define CHANGE_PORT  13

static char kerneldata[] = {"tft_hx8347g"};
uint16_t bytesLength;

int readIntVal;
int error ,ret; 

static volatile __u32 *gpio_direction_reg;
static volatile __u32 *gpio_value_reg;
static volatile __u32 *gpio_value_reg_arr[6];
uint32_t pin_value_addr_offset_arr[6] = {PIN_MOSI_VALUE_ADDR_OFFSET,PIN_MISO_VALUE_ADDR_OFFSET,PIN_CLK_VALUE_ADDR_OFFSET,
									PIN_CS_VALUE_ADDR_OFFSET,PIN_RESET_VALUE_ADDR_OFFSET,PIN_DC_VALUE_ADDR_OFFSET};
uint8_t  pin_num_arr[6]={PIN_NUM_MOSI,PIN_NUM_MISO,PIN_NUM_CLK,PIN_NUM_CS,PIN_NUM_RESET,PIN_NUM_DC};
uint32_t pin_lvl_hi_arr[6] ;
uint32_t pin_lvl_lo_arr[6];

struct CzCharDevice
{
	struct cdev cz_cdev;
	int major;
	dev_t dev;
	struct class *cz_char_dev_class;
};
static struct CzCharDevice tft_hx8347gDev;



ssize_t chrdev_read (struct file *filp, char __user *usr, size_t size, loff_t *loff)
{	
	int retvalue = copy_to_user(usr, kerneldata, sizeof(kerneldata));
	if(retvalue == 0){
		printk(KERN_ERR"kernel senddata ok!\r\n");
	}else{
		printk(KERN_ERR"kernel senddata failed!\r\n");
	}		
	printk("tft_hx8347g\r\n");
	return 0;
}

int chrdev_open (struct inode *inode, struct file *finanole)
{
	//printk(KERN_ERR"%s\r\n",__func__);
	return 0;
}

void pin_process(uint8_t pin_id,uint8_t level){
	if (0==level){	
		//拉低	
		* gpio_value_reg_arr[pin_id] &= pin_lvl_lo_arr[pin_id];
	}else{
		//拉高
		* gpio_value_reg_arr[pin_id] |= pin_lvl_hi_arr[pin_id];
	}
}

int us = 1;
void write_bytes(uint16_t writeLength,uint8_t *bytes){
	//printk(KERN_ERR"hx8347 write bytes len = %d\r\n",writeLength);
	int i,j;
	for(i=0;i<writeLength;i++){
		// printk(KERN_ERR"hx8347 write bytes 0x%X\r\n",byte);
		
		for(j=0;j<8;j++){	
				  
			* gpio_value_reg_arr[PIN_ID_CLK] &= pin_lvl_lo_arr[PIN_ID_CLK];//LCD_SCLK_Clr;			
			// ndelay(us);	
			if(bytes[i]&0x80){
				* gpio_value_reg_arr[PIN_ID_MOSI] |= pin_lvl_hi_arr[PIN_ID_MOSI];//LCD_MOSI_Set;
			}
			else{
				* gpio_value_reg_arr[PIN_ID_MOSI] &= pin_lvl_lo_arr[PIN_ID_MOSI];//LCD_MOSI_Clr;
			}
			* gpio_value_reg_arr[PIN_ID_CLK] |= pin_lvl_hi_arr[PIN_ID_CLK];//LCD_SCLK_Set;
			bytes[i]<<=1;
		}	
	}
}

void fill_screen(uint8_t colorH,uint8_t colorL){
	int i,j;
	// uint8_t colorElemet[2] = {colorH,colorL};
	uint8_t c = colorH;
	printk(KERN_ERR"hx8347 fill_screen color 0x%02X%02X\r\n",colorH,colorL);
	for(i=0;i<153600;i++){
		// // printk(KERN_ERR"hx8347 write bytes 0x%X\r\n",byte);
		// uint8_t colorE = colorElemet[i%2];
		c = i%2==0?colorH:colorL;
		for(j=0;j<8;j++){			  
			* gpio_value_reg_arr[PIN_ID_CLK] &= pin_lvl_lo_arr[PIN_ID_CLK];//LCD_SCLK_Clr;
			if(c&0x80){
				* gpio_value_reg_arr[PIN_ID_MOSI] |= pin_lvl_hi_arr[PIN_ID_MOSI];//LCD_MOSI_Set;
			}
			else{
				* gpio_value_reg_arr[PIN_ID_MOSI] &= pin_lvl_lo_arr[PIN_ID_MOSI];//LCD_MOSI_Clr;
			}
			* gpio_value_reg_arr[PIN_ID_CLK] |= pin_lvl_hi_arr[PIN_ID_CLK];//LCD_SCLK_Set;
			c<<=1;
		}	
	}
}
void change_port(uint8_t port){

}

static ssize_t chrdev_write (struct file *filp, const char __user *buf, size_t size, loff_t *off)
{
	switch(buf[0]){
		case PIN_PROCESS:{
			pin_process(buf[1],buf[2]);
		}break;
		case WRITE_BYTES:{
			bytesLength=0;
			bytesLength |= buf[1];
			bytesLength <<= 8;
			bytesLength |= buf[2];
			write_bytes(bytesLength,buf+3);
		}break;
		case FILL_SCREEN:{
			fill_screen(buf[1],buf[2]);
		}break;
		case CHANGE_PORT:{
			change_port(buf[1]);
		}break;
	}	
    return size; /* 已写入多少个数据 */
}

int chrdev_release (struct inode *inode, struct file *file)
{
	//printk(KERN_ERR"%s\r\n",__func__);
	return 0;
}

struct file_operations fops = 
{
	.open    = chrdev_open,
	.read    = chrdev_read,
    .write    = chrdev_write,
	.release = chrdev_release,
};


static int __init chrdev_init(void)
{
	int ret = 0,error = 0;
	int i;
	struct device *devices1;
	error = alloc_chrdev_region(&tft_hx8347gDev.dev,CHRDEV_MINOR,CHRDEV_COUNT,CHRDEV_NAME); // 注册设备号
	printk(KERN_ERR"MAJOR = %d MINOR = %d\r\n",MAJOR(tft_hx8347gDev.dev),MINOR(tft_hx8347gDev.dev));
	if(error < 0){
		printk("alloc_chrdev_region error\r\n");
		ret =  -EBUSY;
		goto fail;
	}
	tft_hx8347gDev.major = MAJOR(tft_hx8347gDev.dev);
	cdev_init(&tft_hx8347gDev.cz_cdev, &fops); // 绑定字符设备操作函数集
	error = cdev_add(&tft_hx8347gDev.cz_cdev,tft_hx8347gDev.dev,CHRDEV_COUNT);   // 添加字符设备
	if(error < 0){
		printk("cdev_add error\r\n");
		ret =  -EBUSY;
		goto fail1;
	}
	
	// 创建类，类名为testledclass
	tft_hx8347gDev.cz_char_dev_class = class_create(THIS_MODULE, CHRDEV_CLASS_NAME);
	if (IS_ERR(tft_hx8347gDev.cz_char_dev_class)){
		printk("class_create error\r\n");
		ret =  -EBUSY;
		goto fail2;
	}
		
	// 创建设备
	devices1 = device_create(tft_hx8347gDev.cz_char_dev_class, NULL, MKDEV(tft_hx8347gDev.major,0), NULL, SUB_DEV_NAME_1);
	if(NULL == devices1){
		printk("device_create error\r\n");
		ret =  -EBUSY;
		goto fail3;
	}

	//初始化 管脚方向
	gpio_direction_reg = (__u32 *)ioremap(GPIO_BASE_ADDRESS+PIN_MOSI_DIRECTION_ADDR_OFFSET, 4);
	printk(KERN_ERR"chrdev_open before setting/MOSI direct addr=0x%4x ,val=0x%4x\r\n",gpio_direction_reg,* gpio_direction_reg);
	// * gpio_direction_reg |= (0xF << ((PIN_NUM_MOSI%8)*4)); 
	* gpio_direction_reg &= ~(0xE << ((PIN_NUM_MOSI%8)*4)); 
	printk(KERN_ERR"chrdev_open after setting/MOSI direct addr=0x%4x ,val=0x%4x\r\n",gpio_direction_reg,* gpio_direction_reg);
	gpio_direction_reg = (__u32 *)ioremap(GPIO_BASE_ADDRESS+PIN_MISO_DIRECTION_ADDR_OFFSET, 4);
	printk(KERN_ERR"chrdev_open before setting/MISO direct addr=0x%4x ,val=0x%4x\r\n",gpio_direction_reg,* gpio_direction_reg);
	// * gpio_direction_reg |= (0xF << ((PIN_NUM_MISO%8)*4)); 
	* gpio_direction_reg &= ~(0xE << ((PIN_NUM_MISO%8)*4)); 
	printk(KERN_ERR"chrdev_open after setting/MOISO direct addr=0x%4x ,val=0x%4x\r\n",gpio_direction_reg,* gpio_direction_reg);
	gpio_direction_reg = (__u32 *)ioremap(GPIO_BASE_ADDRESS+PIN_CLK_DIRECTION_ADDR_OFFSET, 4);
	printk(KERN_ERR"chrdev_open before setting/CLK direct addr=0x%4x ,val=0x%4x\r\n",gpio_direction_reg,* gpio_direction_reg);
	// * gpio_direction_reg |= (0xF << ((PIN_NUM_CLK%8)*4)); 
	* gpio_direction_reg &= ~(0xE << ((PIN_NUM_CLK%8)*4)); 
	printk(KERN_ERR"chrdev_open after setting/CLK direct addr=0x%4x ,val=0x%4x\r\n",gpio_direction_reg,* gpio_direction_reg);
	gpio_direction_reg = (__u32 *)ioremap(GPIO_BASE_ADDRESS+PIN_CS_DIRECTION_ADDR_OFFSET, 4);
	printk(KERN_ERR"chrdev_open before setting/CS_Port_direct addr=0x%4x ,val=0x%4x\r\n",gpio_direction_reg,* gpio_direction_reg);
	// * gpio_direction_reg |= (0xF << ((PIN_NUM_CS%8)*4)); 
	* gpio_direction_reg &= ~(0xE << ((PIN_NUM_CS%8)*4)); 
	printk(KERN_ERR"chrdev_open after setting/CS_Port_direct addr=0x%4x ,val=0x%4x\r\n",gpio_direction_reg,* gpio_direction_reg);
	
	gpio_direction_reg = (__u32 *)ioremap(GPIO_BASE_ADDRESS+PIN_DC_DIRECTION_ADDR_OFFSET, 4);
	* gpio_direction_reg |= (0xF << ((PIN_NUM_DC%8)*4)); 
	printk(KERN_ERR"chrdev_open before setting/PA_Port_direct addr=0x%4x ,val=0x%4x\r\n",gpio_direction_reg,* gpio_direction_reg);
	* gpio_direction_reg &= ~(0xE << ((PIN_NUM_DC%8)*4)); 
	printk(KERN_ERR"chrdev_open after setting/PA_Port_direct addr=0x%4x ,val=0x%4x\r\n",gpio_direction_reg,* gpio_direction_reg);
	
	gpio_direction_reg = (__u32 *)ioremap(GPIO_BASE_ADDRESS+PIN_RESET_DIRECTION_ADDR_OFFSET, 4);
	* gpio_direction_reg |= (0xF << ((PIN_NUM_RESET%8)*4)); 
	printk(KERN_ERR"chrdev_open before setting/PG_Port_direct addr=0x%4x ,val=0x%4x\r\n",gpio_direction_reg,* gpio_direction_reg);
	* gpio_direction_reg &= ~(0xE << ((PIN_NUM_RESET%8)*4)); 
	printk(KERN_ERR"chrdev_open after setting/PG_Port_direct addr=0x%4x ,val=0x%4x\r\n",gpio_direction_reg,* gpio_direction_reg);
	
	//初始化管脚电平寄存器地址
	for(i=0;i<6;i++){
		gpio_value_reg_arr[i]  = (__u32 *)ioremap(GPIO_BASE_ADDRESS + pin_value_addr_offset_arr[i], 4);
		pin_lvl_lo_arr[i] = ~(0x1 << pin_num_arr[i]);
		pin_lvl_hi_arr[i] = 0x1 << pin_num_arr[i];
	}

	return 0;
fail3:	
	class_destroy(tft_hx8347gDev.cz_char_dev_class);/*  删除类 */	
fail2:	
	cdev_del(&tft_hx8347gDev.cz_cdev);/*  删除cdev */
fail1:
	unregister_chrdev_region(tft_hx8347gDev.dev,CHRDEV_COUNT);
fail:
	return ret;
}


static void __exit chrdev_exit(void)
{
	device_destroy(tft_hx8347gDev.cz_char_dev_class,MKDEV(tft_hx8347gDev.major,0));/*  卸载设备1 */
	class_destroy(tft_hx8347gDev.cz_char_dev_class);/*  删除类 */
	cdev_del(&tft_hx8347gDev.cz_cdev);/*  删除cdev */
	unregister_chrdev_region(tft_hx8347gDev.dev,CHRDEV_COUNT);
}

module_init(chrdev_init);
module_exit(chrdev_exit);

MODULE_DESCRIPTION("LaoCheng Always Foget Description,HeHe!");
MODULE_AUTHOR("ChengZhen");
MODULE_LICENSE("GPL");